# @Time : 2021/4/3 9:33
# @Author : Fioman
# @Phone : 13149920693
"""
1. 模块说明: 上料视觉控制卡驱动模块
2. 模块功能: 主要用来和上料视觉控制卡进行通信
"""
from ctypes import *
import gevent
from settings import ZMC_LIB_PATH, AUX_ZMC_LIB_PATH
from tools.hd_logger import HdLogger
from db_tools.db_handler import DbHandler

offlineZmcParamsKey = [
    "offlineGrabVacuumDelay",  # 离线作业抓板吸真空延时
    "offlineBrokenVacuumDelay",  # 离线上料放板破真空延时
    "angularSeparation",  # 四个角分离延时
    "staticTimeDelay",  # 静置延时
    "JitterIntervalDelay",  # 抖动间隔延时
    "ShakeTimes",  # 抖动次数
    "CapturePauseDelay",  # 自动作业抓板停顿延时
    "PutPauseDelay",  # 自动作业放板停顿延时
]


class OfflineZmc(object):
    """
    拍照控制器驱动类
    """

    def __init__(self):
        self.handleRobot = c_longlong()
        self.logger = HdLogger()
        self.errorMsg = ""
        self.tryAgainDuraion = 0.5  # 通信失败,重新试一遍的时间间隔
        self.ip = "192.168.0.10"
        self.db = DbHandler()
        self.tableName = "offlineZmcParams"
        try:
            self.api = cdll.LoadLibrary(ZMC_LIB_PATH)
            self.aux_api = cdll.LoadLibrary(AUX_ZMC_LIB_PATH)
        except Exception as e:
            self.logger.debug("in CamZmc.__init__() error : {}".format(str(e)))
            self.api = None
            self.aux_api = None

    def __del__(self):
        """
        对象被销毁的时候调用次方法.
        :return:
        """
        try:
            self.close_zmc_conn()
        except Exception as e:
            errorInfo = "in OfflineZmc.__init__() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

    def check_connect(self):
        try:
            isConnect = self.get_modbus_bit(0, 1)[0]
            isConnect = True if isConnect == 0 else False
            return isConnect
        except Exception as e:
            errorInfo = "in Offline.check_connect() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return False

    def offline_zmc_start(self):
        """
        拍照控制器启动
        :return:
        """
        bitPos = 0
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in offline_zmc_start() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return ret

    def offline_zmc_stop(self):
        """
        拍照控制器停止
        :return:
        """
        bitPos = 1
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in offline_zmc_stop() 设置 modbus_bit({}) = {} 失败".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def offline_zmc_rs_stop(self):
        """
        拍照控制器设备急停
        :return:
        """
        bitPos = 2
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in offline_zmc_rs_stop() 设置 modbus_bit({}) = {} 失败".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def offline_zmc_reset(self):
        """
        拍照控制器复位
        :return:
        """
        bitPos = 3
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            # 重新试一次
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in offline_zmc_reset() 设置 modbus_bit({}) = {} 失败!".format(bitPos, bitValue)
                return self.errorMsg
        return ret

    def is_running(self):
        """
        获取上料控制器是否是运行状态
        :return:
        """
        bitPos = 100
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in is_running() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def is_stop_state(self):
        """
        获取上料控制器是否是停止状态
        :return:
        """
        bitPos = 101
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in is_stop_state() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def is_rs_stop(self):
        """
        获取上料控制器是否是急停状态
        :return:
        """
        bitPos = 102
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in is_rs_stop() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def is_reset_state(self):
        """
        获取上料控制器是否是复位状态
        :return:
        """
        bitPos = 103
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in is_reset_state() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, val[0]

    def set_table(self, start, num, table):
        """
        将数据写入到寄存器的表中
        :param start:表格的起始位置
        :param num:写入的值个数
        :param table:写入的值列表
        :return:
        """
        value = (c_float * num)(0)
        value[:] = table
        self.aux_api.ZAux_Direct_SetTable.restype = c_int32
        self.aux_api.ZAux_Direct_SetTable.argtype = (c_void_p, c_uint32, c_uint32, c_void_p)

        try:
            res = self.aux_api.ZAux_Direct_SetTable(self.handleRobot, c_int32(start), c_int32(num), value)
        except Exception as e:
            res = -1
            errorInfo = "in Zmc(set_table)  error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in set_table() ZAux_Direct_GetTable() 执行失败"
        return res

    def get_table(self, start, num):
        """
        从底层的表中读取数据table表
        :param start: 读取的起始位置
        :param num: 读取的数据表的个数
        :return:
        """
        value = (c_float * num)()
        self.aux_api.ZAux_Direct_GetTable.restype = c_int32
        self.aux_api.ZAux_Direct_GetTable.argtype = (c_void_p, c_int32, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_Direct_GetTable(self.handleRobot, c_int32(start), c_int32(num), value)
        except Exception as e:
            res = -1
            errorInfo = "in CamZmc.get_table() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in CamZmc.get_table() ZAux_Direct_GetTable 执行失败"

        return res, value[:]

    def get_output(self, portPos):
        """
        获取输出口的状态
        :param portPos:
        :return: 结果码:0后者其他 值也是0或者1
        """
        value = (c_uint32 * 1)()
        self.aux_api.ZAux_Direct_GetOp.restype = c_int32
        self.aux_api.ZAux_Direct_GetOp.argtype = (c_void_p, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_Direct_GetOp(self.handleRobot, c_int32(portPos), value)
        except Exception as e:
            res = -1
            errorInfo = "in get_output() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in get_output(): ZAux_Direct_GetOp() 执行失败"
        return res, value[:][0]

    def set_output(self, port, value):
        """
        输出口控制
        :param port:
        :param value:
        :return:
        """
        self.aux_api.ZAux_Direct_SetOp.restype = c_int32
        self.aux_api.ZAux_Direct_SetOp.argtype = (c_void_p, c_int32, c_uint32)
        try:
            res = self.aux_api.ZAux_Direct_SetOp(self.handleRobot, c_int32(port), c_uint32(value))
        except Exception as e:
            res = -1
            errorMsg = "in set_output() error: {}".format(str(e))
            print(errorMsg)
            self.logger.debug(errorMsg)
        if res != 0:
            self.errorMsg = "in set_output(): 输出口设置失败"
        return res

    def connect_zmc(self, ip):
        """
        拍照控制器连接接口
        :param ip 设备的IP地址
        :return:
        """
        if isinstance(ip, type(" ")):
            ip = ip.encode('ascii')
        self.api.ZMC_OpenEth.restype = c_int64
        self.api.ZMC_OpenEth.argtype = (c_char_p, c_void_p)
        status = self.api.ZMC_OpenEth(ip, byref(self.handleRobot))
        if status == 0:
            self.errorMsg = ""
        else:
            self.errorMsg = "拍照控制器连接失败,{}".format(status)
        return status

    def close_zmc_conn(self):
        """
        关闭zmc连接
        :return:
        """
        self.api.ZMC_Close.restype = c_int32
        self.api.ZMC_Close.argtype = c_void_p
        status = self.api.ZMC_Close(self.handleRobot)
        return status

    def set_modbus_bit(self, pos, value):
        """
        设置modbus的位寄存器
        :param pos: 设置的bit位位置
        :param value:设置的值
        :return:
        """
        value = (c_uint8 * 1)(value)
        self.aux_api.ZAux_Modbus_Set0x.restype = c_int32
        self.aux_api.ZAux_Modbus_Set0x.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Set0x(self.handleRobot, c_uint16(pos), c_uint16(1), value)
        except Exception as e:
            res = -1
            print("in Zmc(set_modbus_bit)  error: {}".format(e))
            self.logger.debug("in  Zmc(set_modbus_bit), error: {}".format(e))

        if res != 0:
            self.errorMsg = "in set_modbus_bit() ZAux_Modbus_Set0x() 执行失败"

        return res

    def get_modbus_bit(self, start, num):
        """
        获取modbus_bit的bit位的值,返回一个列表,里面存放的是所有的bit位的结果值.
        :param start:获取的bit位的起始位置
        :param num:获取的bit位的个数
        :return:
        """
        value = (c_uint8 * num)(0)
        self.aux_api.ZAux_Modbus_Get0x.restype = c_int32
        self.aux_api.ZAux_Modbus_Get0x.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Get0x(self.handleRobot, c_uint16(start), c_uint16(num), value)
        except Exception as e:
            res = -1
            errorInfo = "in get_modbus_bit() error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in get_modbus_bit() ZAux_Modbus_Get0x() 执行失败"
        return res, value[:]

    def get_axis_postion(self, axisCounts):
        """
         获取轴的坐标,从0轴开始
        :param axisCounts:轴的个数
        :return:返回轴的坐标的值
        """
        value = (c_float * axisCounts)()
        self.aux_api.ZAux_GetModbusDpos.restype = c_int32
        self.aux_api.ZAux_GetModbusDpos.argtype = (c_void_p, c_int32, c_void_p)
        try:
            res = self.aux_api.ZAux_GetModbusDpos(self.handleRobot, c_int32(axisCounts), value)
        except Exception as e:
            res = -1
            errorInfo = "in CamZmc.get_axis_postion() error:{}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        if res != 0:
            self.errorMsg = "in CamZmc.get_axis_postion(): ZAux_GetModbusDpos() 执行失败"

        return res, value[:]

    def set_modbus_byte(self, bytePos, value):
        """
        设置modbus_byte字节寄存器
        :param bytePos:
        :param value:
        :return:
        """
        value = (c_uint16 * 1)(value)
        self.aux_api.ZAux_Modbus_Set4x.restype = c_int32
        self.aux_api.ZAux_Modbus_Set4x.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Set4x(self.handleRobot, c_uint16(bytePos), c_uint16(1), value)
        except Exception as e:
            res = -1
            errorInfo = "in CamZmc.set_modbus_byte() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in CamZmc.set_modbus_byte() ZAux_Modbus_Set4x 执行失败"

        return res

    def set_modbus_float(self, start, counts, values):
        """
        设置modbus_ieee()浮点数的额寄存器,可以设置number个数,然后value
        :param start:modbus_ieee的起点
        :param counts:设置的个数
        :param values:设置的结果值
        :return:
        """
        values = (c_float * counts)(*values)
        self.aux_api.ZAux_Modbus_Set4x_Float.restype = c_int32
        self.aux_api.ZAux_Modbus_Set4x_Float.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Set4x_Float(self.handleRobot, c_uint16(start), c_uint16(counts), values)
        except Exception as e:
            res = -1
            errorInfo = "in CamZmc.set_modbus_float(),error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
        if res != 0:
            self.errorMsg = "in CamZmc.set_modbus_float() ZAux_Modbus_Set4x_Float() 执行失败"

        return res

    def get_modbus_float(self, start, counts):
        """
        获取modbus_ieee()的值,可以获取多个值
        :param start: modbus_ieee起始位置
        :param counts: 读取的数量
        :return:
        """
        value = (c_float * counts)()
        self.aux_api.ZAux_Modbus_Get4x_Float.restype = c_int32
        self.aux_api.ZAux_Modbus_Get4x_Float.argtype = (c_void_p, c_uint16, c_uint16, c_void_p)

        try:
            res = self.aux_api.ZAux_Modbus_Get4x_Float(self.handleRobot, c_uint16(start), c_uint16(counts), value)
        except Exception as e:
            res = -1
            print(e)

        if res != 0:
            self.errorMsg = "ZAux_Modbus_Get4x_Float 执行失败"
        return res, value[:]

    def excute_zmc_cmd(self, cmd):
        """
        控制执行指令,跟用zdveloper的命令行获取的cmd命令状态是一样的效果
        :param cmd:输入的命令指示
        :return:
        """
        res = b" " * 256
        cmd = cmd.encode('ascii')
        self.api.ZMC_Execute.restype = c_uint32
        self.api.ZMC_Execute.argtype = (c_void_p, c_char_p, c_uint32, c_char_p, c_uint32)
        try:
            value = self.api.ZMC_Execute(self.handleRobot, cmd, 1000, res, 256)
        except Exception as e:
            errorInfo = "in CamZmc.excute_zmc_cmd() error : {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            value = -1
        if value != 0:
            self.errorMsg = "in CamZmc.excute_zmc_cmd() ZMC_Execute() 执行失败"
        return value, res.strip()[:-2]

    def move_abs_four_axis(self, movePos):
        """
        四轴绝对运动,同时移动四个轴,在急停状态下不能移动
        :param movePos 移动到的绝对坐标位置
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(0,1,2,3)")
        cmd = "moveabs(" + str("%.3f" % movePos[0]) + "," + str("%.3f" % movePos[1]) + "," + str("%.3f" % movePos[2]) + "," + str(
            "%.3f" % movePos[3]) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_x(self, dis):
        """
        上料移动X轴
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(0)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_y(self, dis):
        """
        上料移动Y轴
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(1)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_z(self, dis):
        """
        上料移动Z轴
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(2)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_w(self, dis):
        """
        上料移动W轴
        :param dis:移动距离一般是角度
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(3)")
        cmd = "pmove(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_x(self, dis):
        """
        上料移动X轴,绝对移动
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(0)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_y(self, dis):
        """
        上料移动Y轴,绝对移动
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(1)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_z(self, dis):
        """
        上料移动Z轴,绝对移动
        :param dis:移动距离
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(2)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def move_abs_w(self, dis):
        """
        上料移动W轴,绝对移动
        :param dis:移动距离一般是角度
        :return:
        """
        ret = self.is_rs_stop()
        if ret == 1:
            return "设备急停,请先复位设备"
        self.excute_zmc_cmd("base(3)")
        cmd = "moveabs(" + str("%.3f" % dis) + ")"
        return self.excute_zmc_cmd(cmd)

    def set_modbus_string(self, msg):
        """
        可以发送字符串,后期用来备用
        :param msg:发送的消息
        :return:
        """
        maxStrNum = 12
        newMsg = msg
        if len(msg) < maxStrNum:
            n = int((maxStrNum - len(msg)) // 2)
            newMsg = " " * n + msg
        for i in range(0, maxStrNum + 1, 2):
            try:
                b = newMsg[i]
            except Exception as e:
                errorInfo = "in set_modbus_string() error : {}".format(str(e))
                print(errorInfo)
                b = " "
            try:
                a = newMsg[i + 1]
            except Exception as e:
                errorInfo = "in set_modbus_string() error : {}".format(str(e))
                print(errorInfo)
                a = " "

            self.set_modbus_byte(1010 + int(i / 2), (ord(a) << 8) | ord(b))

    def reconnect_offline_zmc(self):
        """
        重新连接上料控制器,直接在camZmc对象中进行连接,不要再写到produce中去了,它的连接它自己负责就可以了.
        :return:
        """
        try:
            self.close_zmc_conn()
        except Exception as e:
            errorInfo = "in OfflineZmc.reconnect_offline_zmc() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)

        status = self.connect_zmc(self.ip)
        if status == 0:
            # 连接成功以后再下发参数
            self.logger.debug("离线上料连接成功!")
            res, info = self.set_offline_zmc_params_to_device()
            if res == -1:
                return info
            else:
                self.logger.debug("离线上料参数下发成功!")
        return "ok" if status == 0 else self.errorMsg

    def set_offline_zmc_params_to_device(self):
        """
        将offline_zmc的参数信息下发到设备中,离线上料的参数分成两个部分
        :return:
        """
        try:
            res, paramsDict = self.db.get_offline_zmc_params()
            if res != "ok":
                return "error", paramsDict
            else:
                paramsDict.pop("key")
                if len(paramsDict.values()) == 0:
                    info = "数据库中无数据,先从底层获取拍照控制器的参数数据"
                    print(info)
                    self.logger.debug(info)
                    return self.write_offline_zmc_params_to_mogodb()
                else:
                    paramsList = self.get_offline_zmc_params_value_list_by_dict(paramsDict)
                    if paramsList is None:
                        info = "离线上料控制器下发参数失败,里面有None值"
                        print(info)
                        self.logger.debug(info)
                    else:
                        # list1 = paramsList[:26]
                        # list2 = paramsList[26:]
                        for i in range(len(paramsList)):
                            ret1 = self.set_modbus_byte(1000+i*2, paramsList[i])
                            if ret1 != 0:
                                gevent.sleep(0.5)
                                ret1 = self.set_modbus_byte(1000 + i * 2, paramsList[i])
                            # 如果写入失败就报错,并且返回-1
                            if ret1 != 0:
                                errorInfo = "in OfflineZmc.set_offline_zmc_params_to_devie() error: 离线上料控制器参数下发失败"
                                print(errorInfo)
                                self.logger.debug(errorInfo)
                                return -1, errorInfo
                        return 0, "ok"

        except Exception as e:
            errorInfo = "in OfflineZmc.set_offline_zmc_params_to_devie() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return -1, errorInfo

    def write_offline_zmc_params_to_mogodb(self):
        """
        将拍照控制器的参数,写入到mongodb数据库中.写入的时候,注意要先将小数的部分取后3位即可,不要搞的小数点那么多.
        :return:
        """
        ret1, val1 = self.get_modbus_float(1000, 8)
        # ret2, val2 = self.get_modbus_float(100, 7)
        if ret1 != 0 :
            return "error", "in OfflineZmc.write_offline_zmc_params_to_mogodb() error: 读取底层数据失败!"
        else:
            # 1.先将val里面的数据转换一下,避免有小数点位数太多的数据
            val = val1
            # val.extend(val2)
            offlineZmcParamsValue = [round(x, 3) for x in val]
            offlineZmcParams = dict(zip(offlineZmcParamsKey, offlineZmcParamsValue))
            return self.db.save_offline_zmc_params(offlineZmcParams)

    @staticmethod
    def get_offline_zmc_params_value_list_by_dict(paramsDict):
        """
        根据参数字典的键值列表获取对应的key对应的value列表,为什么不直接用dict的value,是因为dict的value是无序的,key也是无序的,
        不能保证key刚好对应了设备的value值.
        :return:
        """
        paramsList = [paramsDict.get(key) for key in offlineZmcParamsKey]
        if None in paramsList:
            return None
        else:
            return paramsList

    def is_throw_board(self):
        """
        获取是丢放板的状态确认,bit位置是26,0表示丢板,1表示放板.默认是0丢板
        :return:
        """
        bitPos = 26
        bitCounts = 1
        ret, val = self.get_modbus_bit(bitPos, bitCounts)
        if ret != 0:
            # 重新试一次
            gevent.sleep(0.1)
            ret, val = self.get_modbus_bit(bitPos, bitCounts)
            if ret != 0:
                self.errorMsg = "in is_throw_board() 读取 modbus_bit ({}) 失败".format(bitPos)
                return -1, self.errorMsg
        return 0, True if val[0] == 0 else False

    def web_request_get_offline_zmc_params(self):
        """
        前端界面请求上料的参数
        :return:
        """
        try:
            res, paramsDict = self.db.get_cam_zmc_params(self.tableName)
            if res != "ok":
                return "数据库错误,获取的数据为空"
            else:
                return [paramsDict]
        except Exception as e:
            errorInfo = "in CamZmc.web_request_get_cam_zmc_params() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo

    def web_request_save_offline_zmc_params(self, newParams):
        """
        界面上点击了保存上料控制器的参数
        :param newParams:新的参数
        :return:
        """
        try:
            res, info = self.db.save_offline_zmc_params(newParams)
            connected = self.check_connect()
            if connected:
                self.reconnect_offline_zmc()
            return "ok" if res == "ok" else info
        except Exception as e:
            errorInfo = "in OfflineZmc.web_request_save_offline_zmc_params() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo

    def web_request_start_offline_zmc(self):
        """
        前端界面点击了启动上料设备,单独启动
        :return:
        """
        ret = self.offline_zmc_start()
        return "ok" if ret == 0 else ret

    def web_request_stop_offline_zmc(self):
        """
        前端界面点击了停止上料设备,单独停止
        :return:
        """
        ret = self.offline_zmc_stop()
        return "ok" if ret == 0 else ret

    def web_request_reset_offline_zmc(self):
        """
        前端界面上点击了单独复位设备,单独复位
        :return:
        """
        # self.offline_zmc_rs_stop()
        ret = self.offline_zmc_reset()
        return "ok" if ret == 0 else ret

    def web_request_offline_zmc_switch_throw_board(self):
        """
        前端界面点解了切换丢放板的状态
        :return:
        """
        ret, isThrowBoard = self.is_throw_board()
        if ret != 0:
            return isThrowBoard
        else:
            bitPos = 26
            bitVal = 1 if isThrowBoard else 0
            ret = self.set_modbus_bit(bitPos, bitVal)
            return "ok" if ret == 0 else ret

    def web_request_offline_zmc_allow_catch_board(self):
        """
        前端界面点击了允许抓板的按钮,允许抓板的bit位置是20
        :return:
        """
        bitPos = 20
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in web_request_offline_zmc_allow_catch_board() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return "ok"

    def web_request_offline_zmc_allow_take_board(self):
        """
        前端界面点击了允许下料的按钮,允许抓板的bit位置是21
        :return:
        """
        bitPos = 21
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in web_request_offline_zmc_allow_take_board() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return "ok"

    def web_request_offline_zmc_put_board_finish(self):
        """
        前端界面点击了放板完成的按钮,bit位置是24
        :return:
        """
        bitPos = 24
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in web_request_offline_zmc_put_board_finish() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return "ok"

    def web_request_offline_zmc_hand_put_board_confirm(self):
        """
        前端界面上点击了手动放板确认按钮,bit位置是25
        :return:
        """
        bitPos = 25
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in web_request_offline_zmc_hand_put_board_confirm() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return "ok"

    def web_request_offline_zmc_car_is_in_place(self):
        """
        前端界面上点击了小车到位确认按钮,bit位置是30
        :return:
        """
        bitPos = 30
        bitValue = 1
        ret = self.set_modbus_bit(bitPos, bitValue)
        if ret != 0:
            gevent.sleep(self.tryAgainDuraion)
            ret = self.set_modbus_bit(bitPos, bitValue)
            if ret != 0:
                self.errorMsg = "in web_request_offline_zmc_car_is_in_place() 设置 modbus_bit({}) = {} 失败. ".format(bitPos, bitValue)
            return self.errorMsg
        return "ok"

    def get_shielding_start(self):
        shieldStart = []
        ret, val = self.get_modbus_bit(200, 1)
        if val[0] == 1:
            shieldStart.append(True)
        else:
            shieldStart.append(False)
        ret, val = self.get_modbus_bit(201, 1)
        if val[0] == 1:
          shieldStart.append(True)
        else:
          shieldStart.append(False)
        ret, val = self.get_modbus_bit(202, 1)
        if val[0] == 1:
          shieldStart.append(True)
        else:
          shieldStart.append(False)
        ret, val = self.get_modbus_bit(203, 1)
        if val[0] == 1:
          shieldStart.append(True)
        else:
          shieldStart.append(False)
        ret, val = self.get_modbus_bit(204, 1)
        if val[0] == 1:
          shieldStart.append(True)
        else:
          shieldStart.append(False)
        return shieldStart




if __name__ == '__main__':
    offlineZmc = OfflineZmc()
    isOk = offlineZmc.reconnect_offline_zmc()
    print(offlineZmc.set_modbus_byte(1000, 100))
    print("connectOk = {}".format(isOk))
